package sc.senai.br.avaliacao;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public final class ComiteImpl extends UnicastRemoteObject implements Comite {

    private final Map<String, Campeonato> campeonatos;
    private final Map<String, Jogador> jogadores;
    private final Map<String, String> nomes;
    private static final int REGRA_VITORIA = 3;
    private static final int QTD_JOGADORES_MAXIMO = 10;
    private static final int QTD_JOGADORES_MINIMO = 2;
    private static final int PORTA_RMI = 1099;
    private static final String SERVICO = "Comite";

    public ComiteImpl() throws RemoteException {
        this.campeonatos = new ConcurrentHashMap();
        this.jogadores = new ConcurrentHashMap();
        this.nomes = new ConcurrentHashMap();
        
        try {
            LocateRegistry.createRegistry(1099);
            Naming.rebind("rmi://localhost:1099/Comite", this);
        } catch (MalformedURLException | RemoteException e) {
            System.out.println("ERRO: " + e);
        }
        System.out.println("---- Comitê Atlético ----");
    }

    public String registra(Campeonato campeonato) throws RemoteException {
        String nome = null;
        try {
            nome = campeonato.getNome();
        } catch (RemoteException ex) {
            System.out.println("ERRO:" + ex);
            throw new RemoteException("Erro ao obter o nome do estádio!");
        }
        String registro = null;
        try {
            registro = getRegistro(nome);
            this.campeonatos.put(registro, campeonato);
        } catch (RemoteException ex) {
            System.out.println("ERRO:" + ex);
            throw ex;
        }
        System.out.println(String.format("Campeonato '%s' registrado com sucesso! Registro %s", new Object[] { nome, registro }));

        return registro;
    }

    public String registra(Jogador jogador) throws RemoteException {
        String nome = null;
        try {
            nome = jogador.getNome();
        } catch (RemoteException ex) {
            System.out.println("ERRO:" + ex);
            throw new RemoteException("Erro ao obter o nome do jogador!");
        }
        String registro = null;
        try {
            registro = getRegistro(nome);
            this.jogadores.put(registro, jogador);
        } catch (RemoteException ex) {
            System.out.println("ERRO:" + ex);
            throw ex;
        }
        System.out.println(String.format("Jogador '%s' registrado com sucesso! Registro %s", new Object[] { nome, registro }));

        return registro;
    }

    protected String getRegistro(String nome) throws RemoteException {
        nome = nome == null ? "" : nome.trim();
        if (nome.isEmpty()) {
            throw new RemoteException("Nomes em branco não são aceitos.");
        }
        if (this.nomes.containsKey(nome)) {
            throw new RemoteException("Já há registro para este nome.");
        }
        String registro = UUID.randomUUID().toString();
        this.nomes.put(registro, nome);
        return registro;
    }

    public Collection<Jogador> getJogadores(String registro) throws RemoteException {
        if (!this.campeonatos.containsKey(registro)) {
            throw new RemoteException("Campeonato não registrado!");
        }
        if (this.jogadores.size() < 2) {
            return new HashSet<Jogador>();
        }
        int qtdJogadores = new Random().nextInt(10) + 1;
        qtdJogadores = qtdJogadores < 2 ? 2 : qtdJogadores;
        qtdJogadores = qtdJogadores > this.jogadores.size() ? this.jogadores.size() : qtdJogadores;
        HashSet<Jogador> selecionados = new HashSet<Jogador>();

        Object[] keys = this.jogadores.keySet().toArray();
        while (selecionados.size() < qtdJogadores) {
            Object key = keys[new Random().nextInt(keys.length)];
            selecionados.add(this.jogadores.get(key));
        }
        System.out.println(String.format("Campeonato '%s' recebeu inscrição de %02d jogadores", new Object[] { ((Campeonato) this.campeonatos.get(registro)).getNome(), Integer.valueOf(selecionados.size()) }));

        return selecionados;
    }

    public Juiz getJuiz(String registro) throws RemoteException {
        Juiz juiz;
        String campeonato;
        if (this.campeonatos.containsKey(registro)) {
            campeonato = ((Campeonato) this.campeonatos.get(registro)).getNome();
            juiz = new JuizImpl(this, campeonato, 3);
        }
        else {
            throw new RemoteException("Campeonato não registrado!");
        }
        System.out.println("Juiz fornecido para o campeonato '" + campeonato + "' com sucesso!");
        return juiz;
    }

    public String getNomeRegistro(String registro) {
        return (String) this.nomes.get(registro);
    }
}